package top.jiangqiang.qyblog.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.github.yulichang.wrapper.DeleteJoinWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.jiangqiang.qyblog.common.base.query.PageResult;
import top.jiangqiang.qyblog.common.base.response.Result;
import top.jiangqiang.qyblog.common.exception.JsonException;
import top.jiangqiang.qyblog.common.id.IDGenerator;
import top.jiangqiang.qyblog.core.base.service.impl.BaseServiceImpl;
import top.jiangqiang.qyblog.core.constant.ArticleStatus;
import top.jiangqiang.qyblog.core.domain.dto.ArticleQueryDto;
import top.jiangqiang.qyblog.core.domain.dto.ArticleSaveOrUpdateDto;
import top.jiangqiang.qyblog.core.domain.dto.ArticleSettingDto;
import top.jiangqiang.qyblog.core.domain.entity.*;
import top.jiangqiang.qyblog.core.domain.vo.ArticleVo;
import top.jiangqiang.qyblog.core.domain.vo.BlogTagVo;
import top.jiangqiang.qyblog.core.domain.vo.CategoryVo;
import top.jiangqiang.qyblog.core.mapper.ArticleMapper;
import top.jiangqiang.qyblog.core.service.*;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 文章 服务实现类
 * </p>
 *
 * @author JiangQiang
 * @since 2023-05-29
 */
@Service
@RequiredArgsConstructor
public class ArticleServiceImpl extends BaseServiceImpl<ArticleMapper, Article> implements IArticleService {
    private final ITagService tagService;
    private final IArticleTagService articleTagService;
    private final ICategoryService categoryService;
    private final IArticleCategoryService articleCategoryService;
    private final IDraftService draftService;
    private final IDGenerator idGenerator;

    @Override
    public Result<PageResult<ArticleVo>> findByCondition(ArticleQueryDto articleQueryDto) {
        PageResult<ArticleVo> page = getArticleMPJLambdaWrapper()
                .like(StrUtil.isNotBlank(articleQueryDto.getTitle()), Article::getTitle, articleQueryDto.getTitle())
                //状态字段未传，查询所有文章
                .eq(articleQueryDto.getStatus() != null, Article::getStatus, articleQueryDto.getStatus())
                //如果指定了标签id，则查询指定标签id下的文章
                .eq(articleQueryDto.getTagId() != null, ArticleTag::getTagId, articleQueryDto.getTagId())
                //如果指定了分类id，则查询指定分类id下的文章
                .eq(articleQueryDto.getCategoryId() != null, ArticleCategory::getCategoryId, articleQueryDto.getCategoryId())
                .orderByDesc(Article::getSort)
                .orderByDesc(Article::getPublishTime)
                .orderByDesc(Article::getUpdateTime)
                .page(articleQueryDto.toPage(), ArticleVo.class);
        return Result.ok(page);
    }

    @Override
    public Result<ArticleVo> getArticleById(Long id) {
        ArticleVo articleVo = getArticleMPJLambdaWrapper()
                .eq(Article::getId, id)
                .one(ArticleVo.class);
        if (articleVo == null) {
            return Result.error("文章不存在");
        } else {
            return Result.ok(articleVo);
        }
    }

    @Override
    public boolean deleteArticleById(Long id) {
        DeleteJoinWrapper<Article> deleteJoinWrapper = deleteJoinWrapper().deleteAll()
                .leftJoin(ArticleTag.class, ArticleTag::getArticleId, Article::getId)
                .leftJoin(ArticleCategory.class, ArticleCategory::getArticleId, Article::getId)
                .eq(Article::getId, id);
        return deleteJoin(deleteJoinWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<ArticleVo> saveOrUpdateArticle(ArticleSaveOrUpdateDto articleSaveOrUpdateDto) {
        Long articleId = articleSaveOrUpdateDto.getId();
        Draft draft = draftService.getById(articleId);
        if (draft == null) {
            //草稿不存在，则不更新，如果文章也不存在，则提示文章不存在
            Result<ArticleVo> articleVoResult = getArticleById(articleId);
            if (articleVoResult.getData() == null) {
                //草稿不存在，并且文章不存在
                throw new JsonException("文章不存在");
            } else {
                return articleVoResult;
            }
        }
        Article article = getById(articleId);
        if (article == null) {
            //文章不存在，新增
            article = typeConverter.convert(draft, Article.class);
            //文章标题为空
            article.setTitle("未命名的文章" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMAT));
            article.setAlias(article.getId().toString());
            article.setStatus(ArticleStatus.NOT_PUBLISHED);
            baseMapper.insert(article);
        } else {
            article.setContent(draft.getContent());
            baseMapper.updateById(article);
        }
        //删除草稿
        draftService.removeById(articleId);
        return getArticleById(articleId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<ArticleVo> setting(ArticleSettingDto articleSettingDto) {
        Long articleId = articleSettingDto.getId();
        Article oldArticle = getById(articleId);
        if (oldArticle == null) {
            throw new JsonException("文章不存在");
        } else {
            String alias = articleSettingDto.getAlias();
            if (!alias.equals(oldArticle.getAlias())) {
                //别名被修改过
                if (lambdaQuery().eq(Article::getAlias, alias).one() != null) {
                    throw new JsonException("文章别名不允许重复");
                }
            }
        }
        if (articleSettingDto.getStatus() == null) {
            //发布状态
            articleSettingDto.setStatus(ArticleStatus.NOT_PUBLISHED);
        }
        if (ArticleStatus.PUBLISHED.equals(articleSettingDto.getStatus())) {
            //已发布
            if (articleSettingDto.getPublishTime() == null) {
                //发布日期
                articleSettingDto.setPublishTime(LocalDateTime.now());
            }
        }

        Article article = typeConverter.convert(articleSettingDto, Article.class);
        article.setContent(oldArticle.getContent());

        if (articleSettingDto.getStatus() == null) {
            //发布状态
            articleSettingDto.setStatus(ArticleStatus.NOT_PUBLISHED);
        }
        baseMapper.updateById(article);

        List<String> tagNames = articleSettingDto.getTagNames();
        List<String> categoryNames = articleSettingDto.getCategoryNames();
        //删除之前的关联关系 如果为null，则不修改关联关系，如果集合.size为0，则删除关联关系
        if (tagNames != null) {
            articleTagService.lambdaUpdate().eq(ArticleTag::getArticleId, articleId).remove();
        }
        if (categoryNames != null) {
            articleCategoryService.lambdaUpdate().eq(ArticleCategory::getArticleId, articleId).remove();
        }
        processingAssociation(articleId, tagNames, categoryNames);
        ArticleVo articleVo = getArticleMPJLambdaWrapper()
                .eq(Article::getId, articleId)
                .one(ArticleVo.class);
        return Result.ok(articleVo);
    }

    /**
     * 处理关联关系
     *
     * @param articleId     关联的文章id
     * @param tagNames      关联的标签列表
     * @param categoryNames 关联的分类列表
     */
    private void processingAssociation(Long articleId, List<String> tagNames, List<String> categoryNames) {
        if (CollUtil.isNotEmpty(tagNames)) {
            for (String tagName : tagNames) {
                ArticleTag articleTag = new ArticleTag();
                articleTag.setArticleId(articleId);
                BlogTagVo tagVo = tagService.getTagByTagName(tagName);
                if (tagVo == null) {
                    Long tagId = tagService.saveTag(tagName);
                    articleTag.setTagId(tagId);
                } else {
                    articleTag.setTagId(tagVo.getId());
                }
                articleTagService.save(articleTag);
            }
        }
        if (CollUtil.isNotEmpty(categoryNames)) {
            for (String categoryName : categoryNames) {
                ArticleCategory articleCategory = new ArticleCategory();
                articleCategory.setArticleId(articleId);
                CategoryVo category = categoryService.getCategoryByCategoryName(categoryName);
                if (category == null) {
                    Long categoryId = categoryService.saveCategory(categoryName);
                    articleCategory.setCategoryId(categoryId);
                } else {
                    articleCategory.setCategoryId(category.getId());
                }
                articleCategoryService.save(articleCategory);
            }
        }
    }

    /**
     * 文章关联分类和标签查询公共片段
     *
     * @return
     */
    private MPJLambdaWrapper<Article> getArticleMPJLambdaWrapper() {
        return lambdaJoinWrapper().selectAll(Article.class)
                .selectCollection(BlogTag.class, ArticleVo::getBlogTagList)
                .leftJoin(ArticleTag.class, ArticleTag::getArticleId, Article::getId)
                .leftJoin(BlogTag.class, BlogTag::getId, ArticleTag::getTagId)
                .selectCollection(Category.class, ArticleVo::getCategoryList)
                .leftJoin(ArticleCategory.class, ArticleCategory::getArticleId, Article::getId)
                .leftJoin(Category.class, Category::getId, ArticleCategory::getCategoryId);
    }
}
